<template>
  <div class="excel-viewer" :class="isZooming && 'is-zooming'">
    <OUpload v-if="local" :onBeforeUpload="beforeUploadSign" accept=".xlsx,.xls" :modelValue="[]">
      <OButton>选择文件</OButton>
    </OUpload>
    <!-- 错误和加载状态显示保持不变 -->
    <div v-if="error" class="error-message">{{ error }}</div>
    <div v-else-if="loading" class="loading-message">加载 Excel 文件中...</div>
    <div v-else-if="sheets.length === 0" class="no-data-message">没有可展示的数据</div>

    <!-- 主要内容区域 -->
    <div v-else class="excel-content">
      <div class="sheet-tabs">
        <OTab v-model="activeSheet" :line="false">
          <OTabPane v-for="(sheet, index) in sheets" :key="index" :value="index" :label="sheet.name"></OTabPane>
        </OTab>
      </div>
      <div class="zoom-wrapper" @click="toggleZoom">
        <div class="zoom-content">
          <OIcon>
            <IconZoomOut v-if="!isZooming"></IconZoomOut>
            <IconZoomIn v-if="isZooming"></IconZoomIn>
          </OIcon>
        </div>

      </div>
      <div class="sheet-container">
        <table v-if="activeSheetData.length">
          <template v-for="(row, rowIndex) in activeSheetData" :key="rowIndex">
            <tr v-if="shouldRenderRow(row)">
              <template v-for="(cell, colIndex) in row" :key="colIndex">
                <td
                  v-if="shouldRenderCell(cell, row, colIndex)"
                  :rowspan="cell.rowSpan || 1"
                  :colspan="cell.colSpan || 1"
                  :class="{
                    'header-cell': cell.isHeader,
                    'merged-cell': cell.isMerged && !cell.isPrimary,
                    'empty-cell': cell.isEmpty,
                  }"
                >
                  <div class="td-cell" v-html="cell.value || '&nbsp;'">
                  </div>
                </td>
              </template>
            </tr>
          </template>
        </table>
      </div>
    </div>
  </div>
  <ODialog
    v-if="!isZooming"
    main-class="zoom-dialog"
    v-model:visible="zoomVisible"
    @close="toggleZoom"
    hideClose
    phoneHalfFull>
    <ExcelViewer :file="file" :currentSheet="activeSheet" isZooming @zoomIn="toggleZoom" />
  </ODialog>
</template>

<script setup>
import { ref, computed, onMounted, watch } from 'vue';
import * as XLSX from 'xlsx';
import { OButton, ODialog, OIcon, OTab, OTabPane, OUpload, useMessage } from '@opensig/opendesign';
import IconZoomOut from '~icons/app/icon-zoom-out.svg';
import IconZoomIn from '~icons/app/icon-zoom-in.svg';

const props = defineProps({
  file: {
    type: [String, File],
    required: true,
  },
  currentSheet: {
    type: [String, Number],
    default: 0,
  },
  isZooming: {
    type: Boolean,
    default: false,
  },
  autoLoad: {
    type: Boolean,
    default: true,
  },
  headerRows: {
    type: Number,
    default: 1,
  },
  sheet: {
    type: String,
    default: null,
  },
  hideEmptyCells: {
    type: Boolean,
    default: false,
  },
  local: {// 调试属性，从本地获取excel
    type: Boolean,
    default: false,
  },
});

const loading = ref(false);
const error = ref(null);
const sheets = ref([]);
const activeSheet = ref(props.currentSheet);

const message = useMessage();
const beforeUploadSign = async (file) => {
  console.log(file);
  // 校验是否为Excel文件
  if (!['.xlsx', '.xls'].some(type => file.name.endsWith(type))) {
    message.danger({
      content: '请选择Excel文件',
    });
  }
  loadExcel(URL.createObjectURL(file.file));
  return false;
};

const activeSheetData = computed(() => {
  if (sheets.value.length === 0) return [];
  return (sheets.value[activeSheet.value]?.data || []).filter(row => true);
});

// 判断是否应该渲染行
const shouldRenderRow = (row) => {
  return row.some((cell) => !props.hideEmptyCells || (cell && !cell.isEmpty));
};

// 判断是否应该渲染单元格
const shouldRenderCell = (cell, row, colIndex) => {
  if (!cell) return false;
  if (cell.isMerged && !cell.isPrimary) return false; // 不渲染被合并的次要单元格
  if (props.hideEmptyCells && cell.isEmpty) return false;

  // 检查是否是合并单元格的起始单元格
  return true;
};

// 增强的合并单元格处理
const processMerges = (worksheet, data) => {
  if (!worksheet['!merges']) return data;

  const merges = worksheet['!merges'];
  const newData = JSON.parse(JSON.stringify(data));

  merges.forEach((merge) => {
    const { s: start, e: end } = merge;
    const rowSpan = end.r - start.r + 1;
    const colSpan = end.c - start.c + 1;

    // 标记主单元格
    if (newData[start.r] && newData[start.r][start.c]) {
      newData[start.r][start.c] = {
        ...newData[start.r][start.c],
        rowSpan,
        colSpan,
        isMerged: true,
        isPrimary: true,
      };
    }

    // 标记被合并的单元格
    for (let r = start.r; r <= end.r; r++) {
      for (let c = start.c; c <= end.c; c++) {
        if (r === start.r && c === start.c) continue; // 跳过主单元格

        if (newData[r] && newData[r][c]) {
          newData[r][c] = {
            ...newData[r][c],
            isMerged: true,
            isPrimary: false,
            isEmpty: true,
          };
        }
      }
    }
  });

  return newData;
};

// 标记空单元格
const markEmptyCells = (data) => {
  return data.map((row) => {
    return row.map((cell) => {
      return {
        ...cell,
        isEmpty: cell.value === null || cell.value === undefined || cell.value === '',
      };
    });
  });
};

// 转换工作表数据
const convertSheetData = (worksheet, headerRows) => {
  const range = XLSX.utils.decode_range(worksheet['!ref']);
  const data = [];

  // 初始化二维数组
  for (let r = range.s.r; r <= range.e.r; r++) {
    data[r] = [];
    for (let c = range.s.c; c <= range.e.c; c++) {
      const cellAddress = XLSX.utils.encode_cell({ r, c });
      const cell = worksheet[cellAddress];

      data[r][c] = {
        value: cell ? cell.v : '',
        isHeader: r < headerRows,
        isMerged: false,
        isPrimary: true,
        isEmpty: false,
        rowSpan: 1,
        colSpan: 1,
      };
    }
  }

  // 处理合并单元格
  const mergedData = processMerges(worksheet, data);

  // 标记空单元格
  return markEmptyCells(mergedData);
};

const loadExcel = async (fileUrl) => {
  try {
    loading.value = true;
    error.value = null;
    sheets.value = [];

    let workbook;
    let arrayBuffer;

    if (fileUrl) {
      const response = await fetch(fileUrl);
      if (!response.ok) throw new Error('文件下载失败');
      arrayBuffer = await response.arrayBuffer();
    } else if (props.file instanceof File) {
      arrayBuffer = await props.file.arrayBuffer();
    } else if (typeof props.file === 'string') {
      const response = await fetch(props.file);
      if (!response.ok) throw new Error('文件下载失败');
      arrayBuffer = await response.arrayBuffer();
    } else {
      throw new Error('不支持的文件类型');
    }

    workbook = XLSX.read(arrayBuffer, { type: 'array' });

    const sheetData = workbook.SheetNames.map((name, index) => {
      const worksheet = workbook.Sheets[name];
      return {
        name,
        index,
        data: convertSheetData(worksheet, props.headerRows),
      };
    });

    // 如果有指定 sheet，则直接定位到该 sheet
    if (props.sheet) {
      const targetIndex = workbook.SheetNames.indexOf(props.sheet);
      if (targetIndex >= 0) {
        activeSheet.value = targetIndex;
      }
    }

    sheets.value = sheetData.filter((sheet) => sheet.data.some((row) => row.some((cell) => !cell.isEmpty || cell.isMerged))).map(sheet => {
      return {
        ...sheet,
        data: sheet.data.filter(row => row.some(cell => !cell.isEmpty || cell.isMerged)), // 排除空白行
      };
    });

    if (sheets.value.length === 0) {
      error.value = 'Excel 文件中没有有效数据';
    }
  } catch (err) {
    console.error('加载 Excel 文件失败:', err);
    error.value = `加载 Excel 文件失败: ${ err.message }`;
  } finally {
    loading.value = false;
  }
};

onMounted(() => {
  if (props.autoLoad && props.file) {
    loadExcel();
  }
});

watch(
  () => props.file,
  () => {
    loadExcel();
  },
);


watch(
  () => props.sheet,
  (newVal) => {
    if (newVal && sheets.value.length > 0) {
      const targetIndex = sheets.value.findIndex((s) => s.name === newVal);
      if (targetIndex >= 0) {
        activeSheet.value = targetIndex;
      }
    }
  },
);

// -------------------- 切换放大 --------------------
const emits = defineEmits(['zoomIn', 'zoomOut']);
const zoomVisible = ref(false);

const toggleZoom = () => {
  if (props.isZooming) {
    emits('zoomIn');
  } else {
    zoomVisible.value = !zoomVisible.value;
    emits(zoomVisible.value ? 'zoomOut' : 'zoomIn');
  }
};

</script>

<style scoped lang="scss">
/* 外层容器 */
.excel-viewer {
  width: 100%;
  height: 100%;
  max-width: 100%;
  margin-top: 18px;

  .excel-content {
    height: 100%;
  }

  &.is-zooming {
    margin-top: 0;

    .sheet-tabs {
      display: none;
    }

    .sheet-container {
      margin-top: 0;
    }
  }

  /* Sheet 标签容器 */
  .sheet-tabs {
    display: flex;
    gap: 8px;
    margin-bottom: 16px;
    flex-wrap: wrap;
  }

  .zoom-wrapper {
    height: 0;
    position: relative;
    top: 8px;
    right: 8px;
    z-index: 2;
    float: right;

    .zoom-content {
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      width: 32px;
      height: 32px;
      background-color: rgba(var(--o-black), .4);
      border-radius: 4px;
    }

    .o-icon {
      font-size: 24px;
      color: #fff;
    }

    svg, img {
      padding: 0;
      max-width: 100%;
    }
  }

  /* 表格容器 */
  .sheet-container {
    width: 100%;
    height: 100%;
    overflow: auto;
    border: 1px solid var(--o-color-control4);
    border-radius: 4px;
    margin-top: 16px;
    position: relative;


    table {
      //table-layout: fixed;
      width: auto;
      min-width: 100%; /* 最小宽度为100% */
      border-collapse: collapse;
      position: relative;
      white-space: nowrap; /* 防止单元格内容换行 */

      .merged-cell {
        display: none;
      }

      /* 表头样式增强 */
      .header-cell {
        background-color: var(--o-color-control3-light);
        font-weight: 500;
        position: sticky;
        top: 0;
      }

      tr {
        background-color: transparent !important;
        border: none !important;

        td,
        th {
          //border: none !important;
          border: 1px solid var(--o-color-control4) !important;
          text-align: left;
          padding: 8px 12px !important;
          min-width: 88px;
          min-height: 24px;
          width: fit-content;
          max-width: 320px;

          &:first-child {
            border-left: none !important;
          }

          &:last-child {
            //border-right: none !important;
          }

          .td-cell {
            // TODO
            width: 296px;
            white-space: pre-wrap; /* 防止单元格内容换行 */
          }
        }
      }
    }
  }
}

/* 响应式调整 */
@media (max-width: 768px) {
  .sheet-tabs {
    gap: 6px;
  }
  .sheet-tabs button {
    padding: 6px 12px;
    font-size: 13px;
  }
  th,
  td {
    padding: 6px 8px;
    font-size: 14px;
  }
}
</style>
<style lang="scss">
.zoom-dialog {
  --dlg-edge-gap: 12px;
}
</style>